﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Sofire.DataComm.Net.Async
{
    internal class RemoteClient : IRemote
    {
        /// <summary>
        /// 设置或获取一个值，指示当前远程端是否已被终止。
        /// </summary>
        internal bool IsShutdown = false;

        /// <summary>
        /// 表示当前 <see cref="Sofire.DataComm.Net.Async.RemoteClient"/> 是否已接入并填充数据。
        /// </summary>
        private bool IsAccepted = false;

        private readonly SocketAsyncEventArgsServer ReceiveAsyncArgs;
        private readonly AsyncSocketServer OwnerAsyncSocket;

        private Guid _Guid;
        public Guid Guid
        {
            get { return this._Guid; }
        }

        private DateTime _AcceptTime;
        public DateTime AcceptTime
        {
            get { return this._AcceptTime; }
        }

        private object _Tag;
        public object UserToken
        {
            get
            {
                return this._Tag;
            }
            set
            {
                this._Tag = value;
            }
        }

        public RemoteClient(SocketAsyncEventArgsServer receiveAsyncArgs, AsyncSocketServer ownerAsyncSocket)
        {
            this.ReceiveAsyncArgs = receiveAsyncArgs;
            this.OwnerAsyncSocket = ownerAsyncSocket;
        }

        /// <summary>
        /// 与远程端建立连接。
        /// </summary>
        internal void AcceptClient()
        {
            this._Guid = Guid.NewGuid();
            this._AcceptTime = DateTime.Now;
            this.IsShutdown = false;
            this.IsAccepted = true;
            this.ReceiveAsyncArgs.SendAsyncEventArgs.InitSendMode();
        }

        /// <summary>
        /// 与远程端断开连接。
        /// </summary>
        internal void RejectClient()
        {
            this._Guid = Guid.Empty;
            this._AcceptTime = DateTime.MinValue;
            this._Tag = null;
            this.IsAccepted = false;
            this.IsShutdown = true;
            this.ReceiveAsyncArgs.SendAsyncEventArgs.Set();
        }

        #region Full Send Mode

        #region >> Predefine Mode <<

        public void Send(int intValue, string stringValue)
        {
            this.Send(intValue, stringValue, null);
        }

        public void Send(int intValue, string stringValue, object userToken)
        {
            var stringBytes = this.OwnerAsyncSocket.DefaultEncoding.GetBytes(stringValue);
            var stringByteLength = stringBytes.Length;
            byte[] buffer = new byte[stringByteLength + 4];
            int offset = 0;
            BufferConvert.WriteInt32(intValue, buffer, ref offset);
            Buffer.BlockCopy(stringBytes, 0, buffer, offset, stringByteLength);

            this.Send(ReceiveMode.Full, buffer, 0, buffer.Length, null);
        }

        public void Send(string value)
        {
            this.Send(value, null);
        }

        public void Send(string value, object userToken)
        {
            var buffer = this.OwnerAsyncSocket.DefaultEncoding.GetBytes(value);
            this.Send(ReceiveMode.Full, buffer, 0, buffer.Length, null);
        }

        #endregion

        public void Send(byte[] buffer)
        {
            this.Send(ReceiveMode.Full, buffer, 0, buffer.Length, null);
        }

        public void Send(byte[] buffer, int offset, int count)
        {
            this.Send(ReceiveMode.Full, buffer, offset, count, null);
        }

        public void Send(byte[] buffer, object userToken)
        {
            this.Send(ReceiveMode.Full, buffer, 0, buffer.Length, userToken);
        }

        public void Send(byte[] buffer, int offset, int count, object userToken)
        {
            this.Send(ReceiveMode.Full, buffer, offset, count, userToken);
        }

        #endregion

        #region Once Send Mode

        public void OnceSend(byte[] buffer)
        {
            this.Send(ReceiveMode.Once, buffer, 0, buffer.Length, null);
        }

        public void OnceSend(byte[] buffer, object userToken)
        {
            this.Send(ReceiveMode.Once, buffer, 0, buffer.Length, userToken);
        }

        public void OnceSend(byte[] buffer, int offset, int count)
        {
            this.Send(ReceiveMode.Once, buffer, offset, count, null);
        }

        public void OnceSend(byte[] buffer, int offset, int count, object userToken)
        {
            this.Send(ReceiveMode.Once, buffer, offset, count, userToken);
        }

        #endregion

        #region None Send Mode

        public void NoneSend(byte[] buffer)
        {
            this.Send(ReceiveMode.None, buffer, 0, buffer.Length, null);
        }

        public void NoneSend(byte[] buffer, object userToken)
        {
            this.Send(ReceiveMode.None, buffer, 0, buffer.Length, userToken);
        }

        public void NoneSend(byte[] buffer, int offset, int count)
        {
            this.Send(ReceiveMode.None, buffer, offset, count, null);
        }

        public void NoneSend(byte[] buffer, int offset, int count, object userToken)
        {
            this.Send(ReceiveMode.None, buffer, offset, count, userToken);
        }

        #endregion

        protected void Send(ReceiveMode mode, byte[] buffer, int offset, int count, object userToken)
        {
            if(!this.IsAccepted) throw new NotImplementedException();
            if(this.IsShutdown) throw new ObjectDisposedException("System.Net.Sockets.Socket");

            this.ReceiveAsyncArgs.AsyncServerSocket.SendTo(this.ReceiveAsyncArgs.SendAsyncEventArgs, mode, buffer, 0, buffer.Length, userToken);
        }

        public void Shutdown()
        {
            if(!this.IsAccepted) throw new NotImplementedException();
            this.IsShutdown = true;
        }

    }
}
